// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.api.ads.dfa.matchtables;

import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.ads.dfa.axis.factory.DfaServices;
import com.google.api.ads.dfa.lib.client.DfaSession;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.dfareporting.Dfareporting;
import com.google.api.services.dfareporting.model.UserProfile;
import com.google.api.services.dfareporting.model.UserProfileList;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;

/**
* Creates Match Tables using DT file input.
*
* @author Moshe Kahan
*/
public class CreateMatchTables {

  // Prints out a usage message.
  private static void usage() {
    System.err.println(
        "Usage:"
        + "\n\tCreateMatchTables"
        + " <DT Input File #1>"
        + " <DT Input File #2>"
        + " ..."
        + " <DT Input File #N>"
        + " <Match Table output path>");
    System.exit(1);
  }

  /**
   * CreateMatchTables main method. Expects list of DT files and then MT file output 
   * path as command line arguments.
   */
  public static void main(String[] args) throws IOException {
    TableSettings tableSettings = null;
    try {
      // Read in table settings from properties file.
      tableSettings = TableSettings.getTableSettings("matchtables.properties");
    } catch (IOException e) {
      System.out.println("Error in attempting to read matchtables.properties: " + e);
      e.printStackTrace();
      System.exit(2);
    }

    if (tableSettings.getOauth2ClientId().equals("INSERT_CLIENT_ID_HERE")
        || tableSettings.getOauth2ClientSecret().equals("INSERT_CLIENT_SECRET_HERE")) {
      throw new IllegalArgumentException(
          "Please input your client IDs or secret into the matchtables.properties file. "
          + "See https://code.google.com/apis/console#access");
    } else if (tableSettings.getDfaUserProfileName().equals("INSERT_DFA_USER_PROFILE_NAME_HERE")) {
      throw new IllegalArgumentException(
          "Please input your DFA User Profile name into the matchtables.properties file.");
    }

    // Inputs for DT input file, Match table output path, and field delimiter are required.
    if (args.length < 2) {
      usage();
    }

    // Handle credentialing using OAuth2
    Credential credential = null;
    try {
      credential = new OAuth2CommandLine(
        tableSettings.getOauth2ClientId(),
        tableSettings.getOauth2ClientSecret(),
        tableSettings.getOauth2RefreshToken()).getOAuth2Credential();
    } catch (IOException e) {
      System.out.println("Error in attempting to refresh OAuth2 credentials: " + e);
      e.printStackTrace();
      System.exit(3);
    }

    // Construct a DfaSession.
    DfaSession session = null;
    try {
      session = new DfaSession.Builder()
      .withUsernameAndOAuth2Credential(tableSettings.getDfaUserProfileName(), credential)
      .withEnvironment(DfaSession.Environment.PRODUCTION)
      .build();
    } catch (ValidationException e) {
      System.out.println("Error in attempting to set up DFA SOAP API client session: " + e);
      e.printStackTrace();
      System.exit(4);
    }
    DfaServices dfaServices = new DfaServices();

    Dfareporting dfaReporting = new Dfareporting.Builder(
        new NetHttpTransport(), new JacksonFactory(), credential)
      .setApplicationName("Matchtables")
      .build();

    Long userProfileId = null;
    UserProfileList profiles = dfaReporting.userProfiles().list().execute();
    if ((profiles.getItems() != null) && !profiles.getItems().isEmpty()) {
      for (UserProfile userProfile : profiles.getItems()) {
        if (tableSettings.getDfaUserProfileName().equals(userProfile.getUserName())) {
          userProfileId = userProfile.getProfileId();
        }
      }
    }
    if (userProfileId == null) {
      System.out.println("No DFA Reporting user profile found for "
          + tableSettings.getDfaUserProfileName() + ".");
      System.exit(5);
    }

    // Create LookupObjectManager.
    LookupObjectManager lookupObjectManager = LookupObjectManager.getLookupObjectManager(
        dfaServices, session, dfaReporting, userProfileId, tableSettings);

    try {
      String[] dtFiles = Arrays.copyOf(args, args.length - 1);
      String outputPath = args[args.length - 1];
      validateFilesAndFolder(dtFiles, outputPath);
      System.out.println("Parsing DT Files");
      // Parse lines of DT file and send each line for aggregation to DataTransferFileParser
      // or the lookupObjectManager in our case.
      DataTransferFileScanner scanner = new DataTransferFileScanner(lookupObjectManager,
          lookupObjectManager.getRegexDelimiter());
      scanner.parseDTFiles(dtFiles);
      System.out.println("Parsing DT Files Done");

      // Generate Match Tables.
      System.out.println("Generating Match Tables");
      lookupObjectManager.generateMatchTables(outputPath);
      System.out.println("Generating Match Tables Done");
    } catch (DataTransferFileException e) {
      handleException(e, "Error in attempting to parse Data Transfer files", 5);
    } catch (MatchTableFileException e) {
      handleException(e, "Error in attempting to write to match tables", 6);
    } catch (DfaRemoteException e) {
      handleException(e, "Error in attempting to use DFA Remote API", 7);
    }
  }

  private static void handleException(Exception e, String messge, int exitCode) {
    System.out.print(messge + ": " + e);
    if (e.getCause() != null) {
      System.out.println(" with root cause: " + e.getCause());
      e.getCause().printStackTrace();
    } else {
      System.out.println();
      e.printStackTrace();
    }
    System.exit(exitCode);
  }

  private static void validateFilesAndFolder(String[] files, String folder)
      throws DataTransferFileException, MatchTableFileException {
    for (String file : files) {
      File f = new File(file);
      if (!f.isFile()) {
        throw new DataTransferFileException("Data Transder file: "
            + file + " can not be found.");
      }
    }
    File f = new File(folder);
    if (!f.isDirectory()) {
      throw new MatchTableFileException("Match Table output path: "
          + folder + " can not be found.");
    }
  }
}
